<template>
  <!-- 模板部分保持不变 -->
  <Dialog v-model="dialogVisible" title="菜单权限" scroll :max-height="600">
    <el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="80px">
      <el-form-item label="角色名称">
        <el-tag>{{ formData.name }}</el-tag>
      </el-form-item>
      <el-form-item label="角色标识">
        <el-tag>{{ formData.code }}</el-tag>
      </el-form-item>
      <el-form-item label="菜单权限">
        <el-card class="w-full h-400px !overflow-y-scroll" shadow="never">
          <template #header>
            全选/全不选:
            <el-switch
              v-model="treeNodeAll"
              active-text="是"
              inactive-text="否"
              inline-prompt
              @change="handleCheckedTreeNodeAll"
              :disabled="menuLoading"
            />
            全部展开/折叠:
            <el-switch
              v-model="menuExpand"
              active-text="展开"
              inactive-text="折叠"
              inline-prompt
              @change="handleCheckedTreeExpand"
              :disabled="menuLoading"
            />
          </template>
          <el-tree
            v-loading="menuLoading"
            ref="treeRef"
            :data="menuOptions"
            :props="defaultProps"
            empty-text="加载中，请稍候"
            node-key="id"
            show-checkbox
          />
        </el-card>
      </el-form-item>
      <el-form-item label="APP权限">
        <el-card class="w-full h-400px !overflow-y-scroll" shadow="never">
          <template #header>
            全选/全不选:
            <el-switch
              v-model="appTreeNodeAll"
              active-text="是"
              inactive-text="否"
              inline-prompt
              @change="handleCheckedAppTreeNodeAll"
              :disabled="appLoading"
            />
          </template>
          <el-tree
            v-loading="appLoading"
            ref="appTreeRef"
            :data="appOptions"
            :props="defaultProps"
            empty-text="加载中，请稍候"
            node-key="id"
            show-checkbox
          />
        </el-card>
      </el-form-item>
    </el-form>
    <template #footer>
      <el-button
        :disabled="formLoading || menuLoading || appLoading"
        type="primary"
        @click="submitForm"
      >
        确 定
      </el-button>
      <el-button @click="dialogVisible = false">取 消</el-button>
    </template>
  </Dialog>
</template>
<script lang="ts" setup>
import { defaultProps, handleTree } from '@/utils/tree'
import * as RoleApi from '@/api/system/role'
import * as MenuApi from '@/api/system/menu'
import * as PermissionApi from '@/api/system/permission'

defineOptions({ name: 'SystemRoleAssignMenuForm' })

const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗

const dialogVisible = ref(false)
const formLoading = ref(false)
const menuLoading = ref(false)
const appLoading = ref(false)

const formData = reactive({
  id: undefined,
  name: '',
  code: '',
  menuIds: [] as number[]
})
const formRef = ref()
const menuOptions = ref<any[]>([])
const appOptions = ref<any[]>([])

// 菜单权限相关变量
const menuExpand = ref(false)
const treeRef = ref()
const treeNodeAll = ref(false)

// APP权限相关变量
const appMenuExpand = ref(false)
const appTreeRef = ref()
const appTreeNodeAll = ref(false)

/** 打开弹窗 */
const open = async (row: RoleApi.RoleVO) => {
  dialogVisible.value = true
  resetForm()
  menuOptions.value = handleTree(await MenuApi.getSimpleMenusList())
  appOptions.value = handleTree(await MenuApi.getSimpleAppList())

  formData.id = row.id
  formData.name = row.name
  formData.code = row.code
  formLoading.value = true

  try {
    const allMenuIds = await PermissionApi.getRoleMenuList(row.id)
    formData.menuIds = allMenuIds

    // 分批次设置初始选中状态，避免一次性操作大量DOM
    const batchSetChecked = (ids: number[], index = 0) => {
      if (index >= ids.length) return
      // 每次处理10个节点，避免阻塞
      const batch = ids.slice(index, index + 10)
      batch.forEach((menuId) => {
        treeRef.value?.setChecked(menuId, true, false)
        appTreeRef.value?.setChecked(menuId, true, false)
      })
      // 下一批次放到下一个事件循环
      requestAnimationFrame(() => batchSetChecked(ids, index + 10))
    }
    batchSetChecked(allMenuIds)
  } finally {
    formLoading.value = false
  }
}
defineExpose({ open })

/** 提交表单 */
const emit = defineEmits(['success'])
const submitForm = async () => {
  if (!formRef) return
  const valid = await formRef.value.validate()
  if (!valid) return

  formLoading.value = true
  try {
    const menuChecked = [
      ...((treeRef.value?.getCheckedKeys(false) as unknown as Array<number>) || []),
      ...((treeRef.value?.getHalfCheckedKeys() as unknown as Array<number>) || [])
    ]

    const appChecked = [
      ...((appTreeRef.value?.getCheckedKeys(false) as unknown as Array<number>) || []),
      ...((appTreeRef.value?.getHalfCheckedKeys() as unknown as Array<number>) || [])
    ]

    const data = {
      roleId: formData.id,
      menuIds: [...new Set([...menuChecked, ...appChecked])]
    }

    await PermissionApi.assignRoleMenu(data)
    message.success(t('common.updateSuccess'))
    dialogVisible.value = false
    emit('success')
  } finally {
    formLoading.value = false
  }
}

/** 重置表单 */
const resetForm = () => {
  treeNodeAll.value = false
  menuExpand.value = false
  appTreeNodeAll.value = false
  appMenuExpand.value = false

  formData.id = undefined
  formData.name = ''
  formData.code = ''
  formData.menuIds = []

  treeRef.value?.setCheckedNodes([])
  appTreeRef.value?.setCheckedNodes([])
  formRef.value?.resetFields()
}

/** 菜单全选/全不选 */
const handleCheckedTreeNodeAll = async (checked: boolean) => {
  if (menuLoading.value) return

  menuLoading.value = true
  // 先让loading渲染，再执行全选操作
  setTimeout(() => {
    try {
      treeRef.value?.setCheckedNodes(checked ? menuOptions.value : [])
      treeNodeAll.value = checked
    } finally {
      menuLoading.value = false
    }
  }, 0) // 0ms延迟，让浏览器先更新UI
}

/** 菜单展开/折叠全部 - 修复loading延迟显示问题 */
const handleCheckedTreeExpand = async (expand: boolean) => {
  if (menuLoading.value) return

  // 1. 先设置loading为true，让界面立即渲染loading状态
  menuLoading.value = true

  // 2. 用setTimeout将DOM操作延迟到下一个事件循环，确保loading先显示
  setTimeout(() => {
    try {
      const nodes = treeRef.value?.store.nodesMap
      if (nodes) {
        // 分批次更新节点，避免一次性操作大量DOM
        const nodeKeys = Object.keys(nodes)
        const batchUpdate = (index = 0) => {
          if (index >= nodeKeys.length) {
            menuExpand.value = expand
            return
          }
          // 每次处理20个节点，减少单次DOM操作压力
          const end = Math.min(index + 20, nodeKeys.length)
          for (let i = index; i < end; i++) {
            nodes[nodeKeys[i]].expanded = expand
          }
          // 下一批次用requestAnimationFrame，配合浏览器重绘节奏
          requestAnimationFrame(() => batchUpdate(end))
        }
        batchUpdate()
      }
    } finally {
      // 3. 所有操作完成后关闭loading
      menuLoading.value = false
    }
  }, 0)
}

/** APP全选/全不选 */
const handleCheckedAppTreeNodeAll = async (checked: boolean) => {
  if (appLoading.value) return

  appLoading.value = true
  setTimeout(() => {
    try {
      appTreeRef.value?.setCheckedNodes(checked ? appOptions.value : [])
      appTreeNodeAll.value = checked
    } finally {
      appLoading.value = false
    }
  }, 0)
}

/** APP展开/折叠全部 */
const handleCheckedAppTreeExpand = async (expand: boolean) => {
  if (appLoading.value) return

  appLoading.value = true
  setTimeout(() => {
    try {
      const nodes = appTreeRef.value?.store.nodesMap
      if (nodes) {
        const nodeKeys = Object.keys(nodes)
        const batchUpdate = (index = 0) => {
          if (index >= nodeKeys.length) {
            appMenuExpand.value = expand
            return
          }
          const end = Math.min(index + 20, nodeKeys.length)
          for (let i = index; i < end; i++) {
            nodes[nodeKeys[i]].expanded = expand
          }
          requestAnimationFrame(() => batchUpdate(end))
        }
        batchUpdate()
      }
    } finally {
      appLoading.value = false
    }
  }, 0)
}
</script>
